using System;

using GL = MonoMac.OpenGL.GL;
using MonoMac.OpenGL;

namespace Storyteller.Framework.Graphics
{
	public class RenderTexture : Texture
	{
		public RenderTexture(int width, int height)
			: base()
		{
			GL.GetInteger(GetPName.FramebufferBinding, out fbo);
			GL.BindFramebuffer(FramebufferTarget.Framebuffer, fbo);

			this.width = width;
			this.height = height;

			GL.GenFramebuffers(1, out frameBufferObject);
			GL.GenTextures(1, out textureId);

			GL.BindTexture(TextureTarget.Texture2D, textureId);
			GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
			GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
			GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int)TextureWrapMode.ClampToEdge);
			GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int)TextureWrapMode.ClampToEdge);
			GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, width, height, 0,
				PixelFormat.Bgra, PixelType.UnsignedByte, (IntPtr)null);

			GL.BindFramebuffer(FramebufferTarget.Framebuffer, frameBufferObject);
			GL.FramebufferTexture2D(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0, TextureTarget.Texture2D, textureId, 0);
			GL.BindFramebuffer(FramebufferTarget.Framebuffer, fbo);

			FramebufferErrorCode status = GL.CheckFramebufferStatus(FramebufferTarget.Framebuffer);

			if (status != FramebufferErrorCode.FramebufferComplete)
			{
				throw new InvalidOperationException("Failed to create RenderTexture");
			}
		}
		
		public void Bind()
		{
			GL.BindFramebuffer(FramebufferTarget.Framebuffer, frameBufferObject);

			GL.GetInteger(GetPName.Viewport, viewport);
			GL.Viewport(0, 0, Width, Height);

			GL.ClearColor(1, 0, 1, 1);
			GL.Clear(ClearBufferMask.ColorBufferBit);
		}
		
		public void Unbind()
		{
			GL.BindFramebuffer(FramebufferTarget.Framebuffer, fbo);

			GL.Viewport(viewport[0], viewport[1], viewport[2], viewport[3]);
		}

		protected override void Dispose(bool disposing)
		{
			if (!disposed)
			{
				if (disposing)
				{
					// dispose of managed resources
				}

				// dispose of unmanaged resources
				GL.DeleteFramebuffers(1, ref frameBufferObject);

				disposed = true;
			}

			base.Dispose(disposing);
		}

		bool disposed = false;

		int fbo = 0;
		uint frameBufferObject;
		int[] viewport = new int[4];
	}
}
